In this notebook, we do a bit of exploration on our IPUMSR data.

library(ipumsr)
library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(sf)
Linking to GEOS 3.9.3, GDAL 3.5.2, PROJ 8.2.1; sf_use_s2() is TRUE
library(tidycensus)
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
rel_file <- 'nhgis0005_shape/nhgis0005_shapefile_tl2008_us_tract_1940.zip'

cens1940 <- ipumsr::read_nhgis('../data/nhgis0005_csv.zip')
Use of data from NHGIS is subject to conditions including that users should cite the data appropriately. Use command `ipums_conditions()` for more details.

indexed 805.00B in  0s, 12.99MB/s
                                                                         
indexed 2.15GB in  0s, 2.15GB/s
                                                                         
Rows: 7467 Columns: 114── Column specification ───────────────────────────────────────────────────
Delimiter: ","
chr   (9): GISJOIN, STATE, STATEA, COUNTY, COUNTYA, PRETRACTA, TRACTA, ...
dbl (105): YEAR, BUB001, BUQ001, BUQ002, BVG001, BVP001, BUH001, BUH002...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
cens1940shp <- ipumsr::read_ipums_sf('../data/nhgis0005_shape.zip', 
                                file_select=rel_file) |>
  select(GISJOIN)
Warning: Using an external vector in selections was deprecated in tidyselect 1.1.0.
Please use `all_of()` or `any_of()` instead.
# Was:
data %>% select(rel_file)

# Now:
data %>% select(all_of(rel_file))

See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
cens1940 |> merge(cens1940shp, by='GISJOIN')

Note that we have 7,465 resultant shapes. That means we lose two tracts worth of data. Let’s see if these are easily resolvable:

# check what is missing
cens1940 |> filter(!GISJOIN %in% cens1940shp$GISJOIN)

Okay, tragically, that’s not as easy to fix as one would hope. If you investigate these further, there doesn’t seem to be any equivalent tracts in our shapefile. Additionally, these tracts don’t seem to be the product of tract splitting, so we can’t just recombine them. We’ll just have to accept the 2 tract data loss.

# rename_map defined elsewhere, just makes variables human readable
cens1940 <- cens1940 |> merge(cens1940shp, by='GISJOIN')
colnames(cens1940) <- rename_map[colnames(cens1940)]

# TIME TO DO VARIABLE REFACTORING
cens1940 <- cens1940 |>
  mutate(
    whiteP    = round(100 * popWhite / popTotal, 2),
    nonWhiteP = round(100 * popNonwhite / popTotal, 2),
    blackP    = round(100 * negroPopTotal / popTotal, 2),
    noSchool   = maleNoSchool + femaleNoSchool,
    elementary = maleElem1to4 + maleElem5to6 + maleElem7to8 + femaleElem1to4 + femaleElem5to6 + 
      femaleElem7to8,
    highSchool = maleHS1to3 + maleHS4 + femaleHS1to3 + femaleHS4,
    college    = maleCollege1to3 + maleCollege4plus + femaleCollege1to3 + femaleCollege4plus,
    noReportSchool = maleNoSchoolReport + femaleNoSchoolReport,
    medMaleSchoolingYears = maleMedianYears,
    medFemaleSchoolingYears = femaleMedianYears,
    pop14Plus = maleInLabor + maleNotInLabor + femaleInLabor + femaleNotInLabor
  ) |>
  mutate(
    employed = maleEmployed + femaleEmployed,
    employedP = round(100 * (maleEmployed + femaleEmployed) / pop14Plus, 2),
    seekWorkP = round(100 * (maleSeekWork + femaleSeekWork) / pop14Plus, 2),
    notInLaborP = round(100 * (maleNotInLabor + femaleNotInLabor) / pop14Plus, 2),
  ) |>  
  mutate(
    profP = round(100 * (maleProf + femaleProf) / employed, 2),
    semiProfP = round(100 * (maleSemiProf + femaleSemiProf) / employed, 2),
    propP = round(100 * (maleProp + femaleProp) / employed, 2),
    clericalP = round(100 * (maleClerical + femaleClerical) / employed, 2),
    craftsP = round(100 * (maleCrafts + femaleCrafts) / employed, 2),
    operativesP = round(100 * (maleOperatives + femaleOperatives) / employed, 2),
    domesticP = round(100 * (maleDomestic + femaleDomestic) / employed, 2),
    serviceP = round(100 * (maleService + femaleService) / employed, 2),
    laborP = round(100 * (maleLabor + femaleLabor) / 100, 2)
  ) |>
  select(GISJOIN, YEAR, STATE, STATEA, COUNTY, COUNTYA, PRETRACTA, TRACTA, POSTTRCTA, AREANAME, geometry, whiteP, nonWhiteP, blackP, 
         noSchool, elementary, highSchool, college, 
         noReportSchool, medMaleSchoolingYears, 
         medFemaleSchoolingYears, employedP, 
         seekWorkP, notInLaborP, profP, semiProfP, 
         propP, clericalP, craftsP, operativesP, 
         domesticP, serviceP, laborP, fam1Detach, 
         fam1Attach, fam2SideBySide, fam2Other, fam3, 
         fam4, fam1to4WithBiz, fam5to9, fam10to19, 
         fam20plus, otherStruct, underPt51, pt51to75, 
         pt76to1, pt1to1p5, pt1p5to2, pt2plus, 
         noReportRoom, tenUnderPt51, tenPt51to75, tenPt76to1, 
         tenPt1to1p5, tenPt1p5to2, tenPt2plus, tenNoReport, 
         noMajorRepair, majorRepair, repairNoReport, radio, 
         noRadio, radioNoReport, refrigMech, refrigIce, 
         refrigOther, refrigNone, refrigNoReport, heatCentral, 
         heatNoCentral, heatNoReport) 

head(cens1940)
# Read in redlining
redlining <- sf::read_sf('../data/shapes/mappinginequality.gpkg') |>
  select(grade) |>
  st_transform('ESRI:102008')

# Merge tracts on redlining neighborhoods
cens1940rdl <- cens1940shp |> 
  sf::st_transform('ESRI:102008') |>
  sf::st_join(redlining) 

# Get areas and drop geometries
cens1940rdl$area <- cens1940rdl |>
  sf::st_area()

cens1940rdl <- st_drop_geometry(cens1940rdl)

# Do manipulations to get percent overlap by GISJOIN by grade
cens1940rdl <- cens1940rdl |> 
  group_by(GISJOIN, grade) |>
  mutate(totAreaGrade=sum(area)) |>
  select(GISJOIN, grade, totAreaGrade) |>
  unique() |>
  ungroup() |>
  group_by(GISJOIN) |>
  mutate(totArea=sum(totAreaGrade)) |> 
  mutate(propArea=totAreaGrade / totArea) |>
  select(GISJOIN, grade, propArea) |>
  na.exclude()

cens1940rdl <- cens1940rdl |> 
  group_by(GISJOIN) |> 
  mutate(maxPropArea = max(propArea))

# Determine the one with maximal overlap.
# We default to accepting the *highest*
# assigned grade, in case of ties.
# This should only work to weaken observed
# disparities.
cens1940rdl <- cens1940rdl |> filter(
  maxPropArea == propArea
) |>
  dplyr::arrange('GISJOIN', 'grade') |>
  distinct(GISJOIN, .keep_all = TRUE) |>
  select(GISJOIN, grade)

# We lose ~700 observations in the process:
cens1940rdl

With redlining data, we can merge it in and start doing some fun stuff!

# save progress
cens1940 |> sf::st_write('../data/shapes/cens1940shapes.shp', append=FALSE)
Warning: Field names abbreviated for ESRI Shapefile driver
Deleting layer `cens1940shapes' using driver `ESRI Shapefile'
Writing layer `cens1940shapes' to data source 
  `../data/shapes/cens1940shapes.shp' using driver `ESRI Shapefile'
Writing 6856 features with 72 fields and geometry type Multi Polygon.

Let’s filter down to the city’s of interest for our propensity matching analysis:

Cool, let’s do some exploration!

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpJbiB0aGlzIG5vdGVib29rLCB3ZSBkbyBhIGJpdCBvZiBleHBsb3JhdGlvbiBvbiBvdXIgSVBVTVNSIGRhdGEuDQoNCmBgYHtyIGxpYnJhcmllc30NCmxpYnJhcnkoaXB1bXNyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoc2YpDQpsaWJyYXJ5KHRpZHljZW5zdXMpDQpgYGANCg0KYGBge3J9DQpyZWxfZmlsZSA8LSAnbmhnaXMwMDA1X3NoYXBlL25oZ2lzMDAwNV9zaGFwZWZpbGVfdGwyMDA4X3VzX3RyYWN0XzE5NDAuemlwJw0KDQpjZW5zMTk0MCA8LSBpcHVtc3I6OnJlYWRfbmhnaXMoJy4uL2RhdGEvbmhnaXMwMDA1X2Nzdi56aXAnKQ0KY2VuczE5NDBzaHAgPC0gaXB1bXNyOjpyZWFkX2lwdW1zX3NmKCcuLi9kYXRhL25oZ2lzMDAwNV9zaGFwZS56aXAnLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZV9zZWxlY3Q9cmVsX2ZpbGUpIHw+DQogIHNlbGVjdChHSVNKT0lOKQ0KDQpjZW5zMTk0MCB8PiBtZXJnZShjZW5zMTk0MHNocCwgYnk9J0dJU0pPSU4nKQ0KYGBgDQoNCk5vdGUgdGhhdCB3ZSBoYXZlIDcsNDY1IHJlc3VsdGFudCBzaGFwZXMuIFRoYXQgbWVhbnMgd2UgbG9zZSB0d28gdHJhY3RzIHdvcnRoIG9mIGRhdGEuIExldCdzIHNlZSBpZiB0aGVzZSBhcmUgZWFzaWx5IHJlc29sdmFibGU6DQoNCmBgYHtyfQ0KIyBjaGVjayB3aGF0IGlzIG1pc3NpbmcNCmNlbnMxOTQwIHw+IGZpbHRlcighR0lTSk9JTiAlaW4lIGNlbnMxOTQwc2hwJEdJU0pPSU4pDQpgYGANCg0KT2theSwgdHJhZ2ljYWxseSwgdGhhdCdzIG5vdCBhcyBlYXN5IHRvIGZpeCBhcyBvbmUgd291bGQgaG9wZS4gSWYgeW91IGludmVzdGlnYXRlIHRoZXNlIGZ1cnRoZXIsIHRoZXJlIGRvZXNuJ3Qgc2VlbSB0byBiZSBhbnkgZXF1aXZhbGVudCB0cmFjdHMgaW4gb3VyIHNoYXBlZmlsZS4gQWRkaXRpb25hbGx5LCB0aGVzZSB0cmFjdHMgZG9uJ3Qgc2VlbSB0byBiZSB0aGUgcHJvZHVjdCBvZiB0cmFjdCBzcGxpdHRpbmcsIHNvIHdlIGNhbid0IGp1c3QgcmVjb21iaW5lIHRoZW0uIFdlJ2xsIGp1c3QgaGF2ZSB0byBhY2NlcHQgdGhlIDIgdHJhY3QgZGF0YSBsb3NzLg0KDQpgYGB7ciByZW5hbWUgbWFwLCBpbmNsdWRlPUZBTFNFfQ0KcmVuYW1lX21hcCA8LSBjKA0KICAjIE1ldGFkYXRhIHdlIGRvbid0IHdhbnQgdG8gcmVuYW1lDQogICdHSVNKT0lOJz0nR0lTSk9JTicsICAgJ1lFQVInPSdZRUFSJywNCiAgJ1NUQVRFJz0nU1RBVEUnLCAgICAgICAnU1RBVEVBJz0nU1RBVEVBJywNCiAgJ0NPVU5UWSc9J0NPVU5UWScsICAgICAnQ09VTlRZQSc9J0NPVU5UWUEnLA0KICAnUFJFVFJBQ1RBJz0nUFJFVFJBQ1RBJywgJ1RSQUNUQSc9J1RSQUNUQScsICAgDQogICdQT1NUVFJDVEEnPSdQT1NUVFJDVEEnLCAnQVJFQU5BTUUnPSdBUkVBTkFNRScsDQogICdnZW9tZXRyeSc9J2dlb21ldHJ5JywNCiAgIyBOVDE6IFBvcHVsYXRpb24gDQogICdCVUIwMDEnID0gInBvcFRvdGFsIiwNCiAgIyBOVDI6IFBvcHVsYXRpb24gYnkgUmFjZQ0KICAnQlVRMDAxJyA9ICJwb3BXaGl0ZSIsICdCVVEwMDInID0gInBvcE5vbndoaXRlIiwNCiAgIyBOVDQ6IE5lZ3JvIFBvcHVsYXRpb24NCiAgJ0JWRzAwMScgPSAibmVncm9Qb3BUb3RhbCIsDQogICMgTlQ1OiBPY2N1cGllZCBEd2VsbGluZyBVbml0cw0KICAnQlZQMDAxJyA9ICJvY2NEd2VsbGluZ1VuaXRzVG90YWwiLA0KICAjIE5UMTU6IFBlcnNvbnMgMjUgWWVhcnMgYW5kIE92ZXIgYnkgU2V4IGFuZCBZZWFycyBvZiBTY2hvb2wgQ29tcGxldGVkDQogICdCVUgwMDEnID0gIm1hbGVOb1NjaG9vbCIsICAgICAgICdCVUgwMDInID0gIm1hbGVFbGVtMXRvNCIsDQogICdCVUgwMDMnID0gIm1hbGVFbGVtNXRvNiIsICAgICAgICdCVUgwMDQnID0gIm1hbGVFbGVtN3RvOCIsDQogICdCVUgwMDUnID0gIm1hbGVIUzF0bzMiLCAgICAgICAgICdCVUgwMDYnID0gIm1hbGVIUzQiLA0KICAnQlVIMDA3JyA9ICJtYWxlQ29sbGVnZTF0bzMiLCAgICAnQlVIMDA4JyA9ICJtYWxlQ29sbGVnZTRwbHVzIiwNCiAgJ0JVSDAwOScgPSAibWFsZU5vU2Nob29sUmVwb3J0IiwgICAgICAgJ0JVSDAxMCcgPSAiZmVtYWxlTm9TY2hvb2wiLA0KICAnQlVIMDExJyA9ICJmZW1hbGVFbGVtMXRvNCIsICAgICAnQlVIMDEyJyA9ICJmZW1hbGVFbGVtNXRvNiIsDQogICdCVUgwMTMnID0gImZlbWFsZUVsZW03dG84IiwgICAgICdCVUgwMTQnID0gImZlbWFsZUhTMXRvMyIsDQogICdCVUgwMTUnID0gImZlbWFsZUhTNCIsICAgICAgICAgICdCVUgwMTYnID0gImZlbWFsZUNvbGxlZ2UxdG8zIiwNCiAgJ0JVSDAxNycgPSAiZmVtYWxlQ29sbGVnZTRwbHVzIiwgJ0JVSDAxOCcgPSAiZmVtYWxlTm9TY2hvb2xSZXBvcnQiLA0KICAjIE5UMTY6IFBlcnNvbnMgMjUgWWVhcnMgYW5kIE92ZXIgYnkgU2V4IGJ5IE1lZGlhbiBZZWFycyBvZiBTY2hvb2wgQ29tcGxldGVkDQogICdCVUkwMDEnID0gIm1hbGVNZWRpYW5ZZWFycyIsICdCVUkwMDInID0gImZlbWFsZU1lZGlhblllYXJzIiwNCiAgIyBOVDIxOiBTZXggYnkgTGFib3IgRm9yY2UgU3RhdHVzIFtQZXJzb25zIDE0IFllYXJzIGFuZCBPdmVyXQ0KICAnQlVXMDAxJyA9ICJtYWxlSW5MYWJvciIsICAgJ0JVVzAwMicgPSAibWFsZU5vdEluTGFib3IiLA0KICAnQlVXMDAzJyA9ICJmZW1hbGVJbkxhYm9yIiwgJ0JVVzAwNCcgPSAiZmVtYWxlTm90SW5MYWJvciIsDQogICMgTlQyMjogU2V4IGJ5IERldGFpbGVkIExhYm9yIEZvcmNlIFN0YXR1cyBbUGVyc29ucyAxNCBZZWFycyBhbmQgT3Zlcl0NCiAgJ0JVWDAwMScgPSAibWFsZUVtcGxveWVkIiwgICAgICAgICAgICdCVVgwMDInID0gIm1hbGVQdWJFbWVyZ1dvcmsiLA0KICAnQlVYMDAzJyA9ICJtYWxlU2Vla1dvcmsiLCAgICAgICAgICAgJ0JVWDAwNCcgPSAibWFsZU5vdEluTGFib3JIb3VzZSIsDQogICdCVVgwMDUnID0gIm1hbGVOb3RJbkxhYm9yU2Nob29sIiwgICAnQlVYMDA2JyA9ICJtYWxlTm90SW5MYWJvclVuYWJsZSIsDQogICdCVVgwMDcnID0gIm1hbGVOb3RJbkxhYm9ySW5zdCIsICAgICAnQlVYMDA4JyA9ICJtYWxlTm90SW5MYWJvck90aGVyIiwNCiAgJ0JVWDAwOScgPSAiZmVtYWxlRW1wbG95ZWQiLCAgICAgICAgICdCVVgwMTAnID0gImZlbWFsZVB1YkVtZXJnV29yayIsDQogICdCVVgwMTEnID0gImZlbWFsZVNlZWtXb3JrIiwgICAgICAgICAnQlVYMDEyJyA9ICJmZW1hbGVOb3RJbkxhYm9ySG91c2UiLA0KICAnQlVYMDEzJyA9ICJmZW1hbGVOb3RJbkxhYm9yU2Nob29sIiwgJ0JVWDAxNCcgPSAiZmVtYWxlTm90SW5MYWJvclVuYWJsZSIsDQogICdCVVgwMTUnID0gImZlbWFsZU5vdEluTGFib3JJbnN0IiwgICAnQlVYMDE2JyA9ICJmZW1hbGVOb3RJbkxhYm9yT3RoZXIiLA0KICAjIE5UMjU6IFBvcHVsYXRpb24gYnkgU2V4IGJ5IE9jY3VwYXRpb25hbCBHcm91cCBbRW1wbG95ZWQgUGVyc29uc10NCiAgJ0JVMDAwMScgPSAibWFsZVByb2YiLCAgICAgICAnQlUwMDAyJyA9ICJtYWxlU2VtaVByb2YiLA0KICAnQlUwMDAzJyA9ICJtYWxlUHJvcCIsICAgICAgICdCVTAwMDQnID0gIm1hbGVDbGVyaWNhbCIsDQogICdCVTAwMDUnID0gIm1hbGVDcmFmdHMiLCAgICAgJ0JVMDAwNicgPSAibWFsZU9wZXJhdGl2ZXMiLA0KICAnQlUwMDA3JyA9ICJtYWxlRG9tZXN0aWMiLCAgICdCVTAwMDgnID0gIm1hbGVTZXJ2aWNlIiwNCiAgJ0JVMDAwOScgPSAibWFsZUxhYm9yIiwgICAgICAnQlUwMDEwJyA9ICJtYWxlTm9PY2NSZXBvcnQiLA0KICAnQlUwMDExJyA9ICJmZW1hbGVQcm9mIiwgICAgICdCVTAwMTInID0gImZlbWFsZVNlbWlQcm9mIiwNCiAgJ0JVMDAxMycgPSAiZmVtYWxlUHJvcCIsICAgICAnQlUwMDE0JyA9ICJmZW1hbGVDbGVyaWNhbCIsDQogICdCVTAwMTUnID0gImZlbWFsZUNyYWZ0cyIsICAgJ0JVMDAxNicgPSAiZmVtYWxlT3BlcmF0aXZlcyIsDQogICdCVTAwMTcnID0gImZlbWFsZURvbWVzdGljIiwgJ0JVMDAxOCcgPSAiZmVtYWxlU2VydmljZSIsDQogICdCVTAwMTknID0gImZlbWFsZUxhYm9yIiwgICAgJ0JVMDAyMCcgPSAiZmVtYWxlTm9PY2NSZXBvcnQiLA0KICAjIE5UMzA6IER3ZWxsaW5nIFVuaXRzIGJ5IFR5cGUgb2YgU3RydWN0dXJlDQogICdCVTYwMDEnID0gImZhbTFEZXRhY2giLCAgICAgJ0JVNjAwMicgPSAiZmFtMUF0dGFjaCIsDQogICdCVTYwMDMnID0gImZhbTJTaWRlQnlTaWRlIiwgJ0JVNjAwNCcgPSAiZmFtMk90aGVyIiwNCiAgJ0JVNjAwNScgPSAiZmFtMyIsICAgICAgICAgICAnQlU2MDA2JyA9ICJmYW00IiwNCiAgJ0JVNjAwNycgPSAiZmFtMXRvNFdpdGhCaXoiLCAnQlU2MDA4JyA9ICJmYW01dG85IiwNCiAgJ0JVNjAwOScgPSAiZmFtMTB0bzE5IiwgICAgICAnQlU2MDEwJyA9ICJmYW0yMHBsdXMiLA0KICAnQlU2MDExJyA9ICJvdGhlclN0cnVjdCIsIA0KICAjIE5UMzI6IE9jY3VwaWVkIER3ZWxsaW5nIFVuaXRzDQogICdCVTgwMDEnID0gInVuZGVyUHQ1MSIsICAgJ0JVODAwMicgPSAicHQ1MXRvNzUiLA0KICAnQlU4MDAzJyA9ICJwdDc2dG8xIiwgICAgICdCVTgwMDQnID0gInB0MXRvMXA1IiwgICAgDQogICdCVTgwMDUnID0gInB0MXA1dG8yIiwgICAgJ0JVODAwNicgPSAicHQycGx1cyIsICAgICANCiAgJ0JVODAwNycgPSAibm9SZXBvcnRSb29tIiwNCiAgIyBOVDMzOiBUZW5hbnQtT2NjdXBpZWQgRHdlbGxpbmcgVW5pdHMNCiAgJ0JVOTAwMScgPSAidGVuVW5kZXJQdDUxIiwgJ0JVOTAwMicgPSAidGVuUHQ1MXRvNzUiLA0KICAnQlU5MDAzJyA9ICJ0ZW5QdDc2dG8xIiwgICAnQlU5MDA0JyA9ICJ0ZW5QdDF0bzFwNSIsDQogICdCVTkwMDUnID0gInRlblB0MXA1dG8yIiwgICdCVTkwMDYnID0gInRlblB0MnBsdXMiLA0KICAnQlU5MDA3JyA9ICJ0ZW5Ob1JlcG9ydCIsDQogICMgTlQ0MzogRHdlbGxpbmcgVW5pdHMgYnkgU3RhdGUgb2YgUmVwYWlyDQogICdCVkswMDEnID0gIm5vTWFqb3JSZXBhaXIiLCAnQlZLMDAyJyA9ICJtYWpvclJlcGFpciIsDQogICdCVkswMDMnID0gInJlcGFpck5vUmVwb3J0IiwNCiAgIyBOVDQ1OiBPY2N1cGllZCBEd2VsbGluZyBVbml0cyBieSBSYWRpbyBPd25lcnNoaXANCiAgJ0JWTTAwMScgPSAicmFkaW8iLCAnQlZNMDAyJyA9ICJub1JhZGlvIiwNCiAgJ0JWTTAwMycgPSAicmFkaW9Ob1JlcG9ydCIsDQogICMgTlQ0NjogT2NjdXBpZWQgRHdlbGxpbmcgVW5pdHMgYnkgUmVmcmlnZXJhdGlvbg0KICAnQlZOMDAxJyA9ICJyZWZyaWdNZWNoIiwgICdCVk4wMDInID0gInJlZnJpZ0ljZSIsDQogICdCVk4wMDMnID0gInJlZnJpZ090aGVyIiwgJ0JWTjAwNCcgPSAicmVmcmlnTm9uZSIsDQogICdCVk4wMDUnID0gInJlZnJpZ05vUmVwb3J0IiwNCiAgIyBOVDQ3OiBPY2N1cGllZCBEd2VsbGluZyBVbml0cyBieSBIZWF0aW5nDQogICdCVk8wMDEnID0gImhlYXRDZW50cmFsIiwgJ0JWTzAwMicgPSAiaGVhdE5vQ2VudHJhbCIsDQogICdCVk8wMDMnID0gImhlYXROb1JlcG9ydCINCikNCmBgYA0KDQpgYGB7cn0NCiMgcmVuYW1lX21hcCBkZWZpbmVkIGVsc2V3aGVyZSwganVzdCBtYWtlcyB2YXJpYWJsZXMgaHVtYW4gcmVhZGFibGUNCmNlbnMxOTQwIDwtIGNlbnMxOTQwIHw+IG1lcmdlKGNlbnMxOTQwc2hwLCBieT0nR0lTSk9JTicpDQpjb2xuYW1lcyhjZW5zMTk0MCkgPC0gcmVuYW1lX21hcFtjb2xuYW1lcyhjZW5zMTk0MCldDQoNCiMgVElNRSBUTyBETyBWQVJJQUJMRSBSRUZBQ1RPUklORw0KY2VuczE5NDAgPC0gY2VuczE5NDAgfD4NCiAgbXV0YXRlKA0KICAgIHdoaXRlUCAgICA9IHJvdW5kKDEwMCAqIHBvcFdoaXRlIC8gcG9wVG90YWwsIDIpLA0KICAgIG5vbldoaXRlUCA9IHJvdW5kKDEwMCAqIHBvcE5vbndoaXRlIC8gcG9wVG90YWwsIDIpLA0KICAgIGJsYWNrUCAgICA9IHJvdW5kKDEwMCAqIG5lZ3JvUG9wVG90YWwgLyBwb3BUb3RhbCwgMiksDQogICAgbm9TY2hvb2wgICA9IG1hbGVOb1NjaG9vbCArIGZlbWFsZU5vU2Nob29sLA0KICAgIGVsZW1lbnRhcnkgPSBtYWxlRWxlbTF0bzQgKyBtYWxlRWxlbTV0bzYgKyBtYWxlRWxlbTd0bzggKyBmZW1hbGVFbGVtMXRvNCArIGZlbWFsZUVsZW01dG82ICsgDQogICAgICBmZW1hbGVFbGVtN3RvOCwNCiAgICBoaWdoU2Nob29sID0gbWFsZUhTMXRvMyArIG1hbGVIUzQgKyBmZW1hbGVIUzF0bzMgKyBmZW1hbGVIUzQsDQogICAgY29sbGVnZSAgICA9IG1hbGVDb2xsZWdlMXRvMyArIG1hbGVDb2xsZWdlNHBsdXMgKyBmZW1hbGVDb2xsZWdlMXRvMyArIGZlbWFsZUNvbGxlZ2U0cGx1cywNCiAgICBub1JlcG9ydFNjaG9vbCA9IG1hbGVOb1NjaG9vbFJlcG9ydCArIGZlbWFsZU5vU2Nob29sUmVwb3J0LA0KICAgIG1lZE1hbGVTY2hvb2xpbmdZZWFycyA9IG1hbGVNZWRpYW5ZZWFycywNCiAgICBtZWRGZW1hbGVTY2hvb2xpbmdZZWFycyA9IGZlbWFsZU1lZGlhblllYXJzLA0KICAgIHBvcDE0UGx1cyA9IG1hbGVJbkxhYm9yICsgbWFsZU5vdEluTGFib3IgKyBmZW1hbGVJbkxhYm9yICsgZmVtYWxlTm90SW5MYWJvcg0KICApIHw+DQogIG11dGF0ZSgNCiAgICBlbXBsb3llZCA9IG1hbGVFbXBsb3llZCArIGZlbWFsZUVtcGxveWVkLA0KICAgIGVtcGxveWVkUCA9IHJvdW5kKDEwMCAqIChtYWxlRW1wbG95ZWQgKyBmZW1hbGVFbXBsb3llZCkgLyBwb3AxNFBsdXMsIDIpLA0KICAgIHNlZWtXb3JrUCA9IHJvdW5kKDEwMCAqIChtYWxlU2Vla1dvcmsgKyBmZW1hbGVTZWVrV29yaykgLyBwb3AxNFBsdXMsIDIpLA0KICAgIG5vdEluTGFib3JQID0gcm91bmQoMTAwICogKG1hbGVOb3RJbkxhYm9yICsgZmVtYWxlTm90SW5MYWJvcikgLyBwb3AxNFBsdXMsIDIpLA0KICApIHw+ICANCiAgbXV0YXRlKA0KICAgIHByb2ZQID0gcm91bmQoMTAwICogKG1hbGVQcm9mICsgZmVtYWxlUHJvZikgLyBlbXBsb3llZCwgMiksDQogICAgc2VtaVByb2ZQID0gcm91bmQoMTAwICogKG1hbGVTZW1pUHJvZiArIGZlbWFsZVNlbWlQcm9mKSAvIGVtcGxveWVkLCAyKSwNCiAgICBwcm9wUCA9IHJvdW5kKDEwMCAqIChtYWxlUHJvcCArIGZlbWFsZVByb3ApIC8gZW1wbG95ZWQsIDIpLA0KICAgIGNsZXJpY2FsUCA9IHJvdW5kKDEwMCAqIChtYWxlQ2xlcmljYWwgKyBmZW1hbGVDbGVyaWNhbCkgLyBlbXBsb3llZCwgMiksDQogICAgY3JhZnRzUCA9IHJvdW5kKDEwMCAqIChtYWxlQ3JhZnRzICsgZmVtYWxlQ3JhZnRzKSAvIGVtcGxveWVkLCAyKSwNCiAgICBvcGVyYXRpdmVzUCA9IHJvdW5kKDEwMCAqIChtYWxlT3BlcmF0aXZlcyArIGZlbWFsZU9wZXJhdGl2ZXMpIC8gZW1wbG95ZWQsIDIpLA0KICAgIGRvbWVzdGljUCA9IHJvdW5kKDEwMCAqIChtYWxlRG9tZXN0aWMgKyBmZW1hbGVEb21lc3RpYykgLyBlbXBsb3llZCwgMiksDQogICAgc2VydmljZVAgPSByb3VuZCgxMDAgKiAobWFsZVNlcnZpY2UgKyBmZW1hbGVTZXJ2aWNlKSAvIGVtcGxveWVkLCAyKSwNCiAgICBsYWJvclAgPSByb3VuZCgxMDAgKiAobWFsZUxhYm9yICsgZmVtYWxlTGFib3IpIC8gMTAwLCAyKQ0KICApIHw+DQogIHNlbGVjdChHSVNKT0lOLCBZRUFSLCBTVEFURSwgU1RBVEVBLCBDT1VOVFksIENPVU5UWUEsIFBSRVRSQUNUQSwgVFJBQ1RBLCBQT1NUVFJDVEEsIEFSRUFOQU1FLCBnZW9tZXRyeSwgd2hpdGVQLCBub25XaGl0ZVAsIGJsYWNrUCwgDQogICAgICAgICBub1NjaG9vbCwgZWxlbWVudGFyeSwgaGlnaFNjaG9vbCwgY29sbGVnZSwgDQogICAgICAgICBub1JlcG9ydFNjaG9vbCwgbWVkTWFsZVNjaG9vbGluZ1llYXJzLCANCiAgICAgICAgIG1lZEZlbWFsZVNjaG9vbGluZ1llYXJzLCBlbXBsb3llZFAsIA0KICAgICAgICAgc2Vla1dvcmtQLCBub3RJbkxhYm9yUCwgcHJvZlAsIHNlbWlQcm9mUCwgDQogICAgICAgICBwcm9wUCwgY2xlcmljYWxQLCBjcmFmdHNQLCBvcGVyYXRpdmVzUCwgDQogICAgICAgICBkb21lc3RpY1AsIHNlcnZpY2VQLCBsYWJvclAsIGZhbTFEZXRhY2gsIA0KICAgICAgICAgZmFtMUF0dGFjaCwgZmFtMlNpZGVCeVNpZGUsIGZhbTJPdGhlciwgZmFtMywgDQogICAgICAgICBmYW00LCBmYW0xdG80V2l0aEJpeiwgZmFtNXRvOSwgZmFtMTB0bzE5LCANCiAgICAgICAgIGZhbTIwcGx1cywgb3RoZXJTdHJ1Y3QsIHVuZGVyUHQ1MSwgcHQ1MXRvNzUsIA0KICAgICAgICAgcHQ3NnRvMSwgcHQxdG8xcDUsIHB0MXA1dG8yLCBwdDJwbHVzLCANCiAgICAgICAgIG5vUmVwb3J0Um9vbSwgdGVuVW5kZXJQdDUxLCB0ZW5QdDUxdG83NSwgdGVuUHQ3NnRvMSwgDQogICAgICAgICB0ZW5QdDF0bzFwNSwgdGVuUHQxcDV0bzIsIHRlblB0MnBsdXMsIHRlbk5vUmVwb3J0LCANCiAgICAgICAgIG5vTWFqb3JSZXBhaXIsIG1ham9yUmVwYWlyLCByZXBhaXJOb1JlcG9ydCwgcmFkaW8sIA0KICAgICAgICAgbm9SYWRpbywgcmFkaW9Ob1JlcG9ydCwgcmVmcmlnTWVjaCwgcmVmcmlnSWNlLCANCiAgICAgICAgIHJlZnJpZ090aGVyLCByZWZyaWdOb25lLCByZWZyaWdOb1JlcG9ydCwgaGVhdENlbnRyYWwsIA0KICAgICAgICAgaGVhdE5vQ2VudHJhbCwgaGVhdE5vUmVwb3J0KSANCg0KaGVhZChjZW5zMTk0MCkNCmBgYA0KDQpgYGB7ciBnZXQgcmVkbGluaW5nIGFzc2lnbm1lbnRzfQ0KIyBSZWFkIGluIHJlZGxpbmluZw0KcmVkbGluaW5nIDwtIHNmOjpyZWFkX3NmKCcuLi9kYXRhL3NoYXBlcy9tYXBwaW5naW5lcXVhbGl0eS5ncGtnJykgfD4NCiAgc2VsZWN0KGdyYWRlKSB8Pg0KICBzdF90cmFuc2Zvcm0oJ0VTUkk6MTAyMDA4JykNCg0KIyBNZXJnZSB0cmFjdHMgb24gcmVkbGluaW5nIG5laWdoYm9yaG9vZHMNCmNlbnMxOTQwcmRsIDwtIGNlbnMxOTQwc2hwIHw+IA0KICBzZjo6c3RfdHJhbnNmb3JtKCdFU1JJOjEwMjAwOCcpIHw+DQogIHNmOjpzdF9qb2luKHJlZGxpbmluZykgDQoNCiMgR2V0IGFyZWFzIGFuZCBkcm9wIGdlb21ldHJpZXMNCmNlbnMxOTQwcmRsJGFyZWEgPC0gY2VuczE5NDByZGwgfD4NCiAgc2Y6OnN0X2FyZWEoKQ0KDQpjZW5zMTk0MHJkbCA8LSBzdF9kcm9wX2dlb21ldHJ5KGNlbnMxOTQwcmRsKQ0KDQojIERvIG1hbmlwdWxhdGlvbnMgdG8gZ2V0IHBlcmNlbnQgb3ZlcmxhcCBieSBHSVNKT0lOIGJ5IGdyYWRlDQpjZW5zMTk0MHJkbCA8LSBjZW5zMTk0MHJkbCB8PiANCiAgZ3JvdXBfYnkoR0lTSk9JTiwgZ3JhZGUpIHw+DQogIG11dGF0ZSh0b3RBcmVhR3JhZGU9c3VtKGFyZWEpKSB8Pg0KICBzZWxlY3QoR0lTSk9JTiwgZ3JhZGUsIHRvdEFyZWFHcmFkZSkgfD4NCiAgdW5pcXVlKCkgfD4NCiAgdW5ncm91cCgpIHw+DQogIGdyb3VwX2J5KEdJU0pPSU4pIHw+DQogIG11dGF0ZSh0b3RBcmVhPXN1bSh0b3RBcmVhR3JhZGUpKSB8PiANCiAgbXV0YXRlKHByb3BBcmVhPXRvdEFyZWFHcmFkZSAvIHRvdEFyZWEpIHw+DQogIHNlbGVjdChHSVNKT0lOLCBncmFkZSwgcHJvcEFyZWEpIHw+DQogIG5hLmV4Y2x1ZGUoKQ0KDQpjZW5zMTk0MHJkbCA8LSBjZW5zMTk0MHJkbCB8PiANCiAgZ3JvdXBfYnkoR0lTSk9JTikgfD4gDQogIG11dGF0ZShtYXhQcm9wQXJlYSA9IG1heChwcm9wQXJlYSkpDQoNCiMgRGV0ZXJtaW5lIHRoZSBvbmUgd2l0aCBtYXhpbWFsIG92ZXJsYXAuDQojIFdlIGRlZmF1bHQgdG8gYWNjZXB0aW5nIHRoZSAqaGlnaGVzdCoNCiMgYXNzaWduZWQgZ3JhZGUsIGluIGNhc2Ugb2YgdGllcy4NCiMgVGhpcyBzaG91bGQgb25seSB3b3JrIHRvIHdlYWtlbiBvYnNlcnZlZA0KIyBkaXNwYXJpdGllcy4NCmNlbnMxOTQwcmRsIDwtIGNlbnMxOTQwcmRsIHw+IGZpbHRlcigNCiAgbWF4UHJvcEFyZWEgPT0gcHJvcEFyZWENCikgfD4NCiAgZHBseXI6OmFycmFuZ2UoJ0dJU0pPSU4nLCAnZ3JhZGUnKSB8Pg0KICBkaXN0aW5jdChHSVNKT0lOLCAua2VlcF9hbGwgPSBUUlVFKSB8Pg0KICBzZWxlY3QoR0lTSk9JTiwgZ3JhZGUpDQoNCiMgV2UgbG9zZSB+NzAwIG9ic2VydmF0aW9ucyBpbiB0aGUgcHJvY2VzczoNCmNlbnMxOTQwcmRsDQpgYGANCg0KV2l0aCByZWRsaW5pbmcgZGF0YSwgd2UgY2FuIG1lcmdlIGl0IGluIGFuZCBzdGFydCBkb2luZyBzb21lIGZ1biBzdHVmZiENCg0KYGBge3IgbWVyZ2UgaW59DQpjZW5zMTk0MCA8LSBjZW5zMTk0MCB8PiBtZXJnZShjZW5zMTk0MHJkbCwgYnk9J0dJU0pPSU4nLCBob3c9J2lubmVyJykNCg0KY2VuczE5NDAgPC0gY2VuczE5NDAgfD4gZmlsdGVyKGdyYWRlICE9ICdFJykNCg0KIyBzYXZlIHByb2dyZXNzDQpjZW5zMTk0MCB8PiBzZjo6c3Rfd3JpdGUoJy4uL2RhdGEvc2hhcGVzL2NlbnMxOTQwc2hhcGVzLnNocCcsIGFwcGVuZD1GQUxTRSkNCg0KY2VuczE5NDAgfD4gaGVhZCgpDQpgYGANCg0KTGV0J3MgZmlsdGVyIGRvd24gdG8gdGhlIGNpdHkncyBvZiBpbnRlcmVzdCBmb3Igb3VyIHByb3BlbnNpdHkgbWF0Y2hpbmcgYW5hbHlzaXM6DQoNCmBgYHtyfQ0KDQpjaXRpZXMgPC0gYygnQ2hpY2FnbycsICdwaGlsYWRlbHBoaWEnLCAnZGV0cm9pdCcsICJsb3MgYW5nZWxlcyIsICduZXcgeW9yayBjaXR5JykNCg0KZmlsdGVyX2Z1bmMgPC0gZnVuY3Rpb24ocGxhY2UpIHsNCiAgcHVycnI6Om1hcChjaXRpZXMsDQogICAgfiBzdHJpbmdyOjpzdHJfZGV0ZWN0KA0KICAgICAgcGxhY2UsIHN0cmluZ3I6OnJlZ2V4KC54LCBpZ25vcmVfY2FzZT1UKQ0KICAgICkNCiAgKSB8Pg0KICBwdXJycjo6cmVkdWNlKGMpIHw+DQogIGFueSgpDQp9DQoNCmZpbHRlcl9mdW5jKCdjaGljYWdvJykNCg0KbWFzayA8LSBwdXJycjo6bWFwKGNlbnMxOTQwJEFSRUFOQU1FLCB+IGZpbHRlcl9mdW5jKC54KSkgfD4gcHVycnI6OnJlZHVjZShjKQ0KbnJvdyhjZW5zMTk0MFttYXNrLF0pDQoNCmBgYA0KDQpDb29sLCBsZXQncyBkbyBzb21lIGV4cGxvcmF0aW9uIQ0KYGBge3J9DQpleGNsdWRlX2xpc3QgPC0gYygnR0lTSk9JTicsICdZRUFSJywgJ1NUQVRFJywgJ1NUQVRFQScsICdDT1VOVFknLCAnQ09VTlRZQScsICdQUkVUUkFDVEEnLCAnVFJBQ1RBJywgJ1BPU1RUUkNUQScsICdBUkVBTkFNRScpDQoNCmFuYWx5c2lzX2RhdGEgPC0gY2VuczE5NDAgfD4gDQogIHNlbGVjdCgtYWxsX29mKGV4Y2x1ZGVfbGlzdCkpIHw+IA0KICBzdF9kcm9wX2dlb21ldHJ5KCkgfD4gDQogIHNlbGVjdCgtZ2VvbWV0cnkpDQoNCmFuYWx5c2lzX2RhdGENCg0KYW5hbHlzaXNfZGF0YSB8PiBtbHI6OnN1bW1hcml6ZUNvbHVtbnMoKQ0KDQpgYGANCg0KYGBge3J9DQphbmFseXNpc19kYXRhX3N0YW5kIDwtIGFuYWx5c2lzX2RhdGEgfD4gbWxyOjpub3JtYWxpemVGZWF0dXJlcyhvbi5jb25zdGFudCA9ICJ3YXJuIikNCg0KZ3JhZGVfYXNzaWducyA8LSBjKCdBJz0nQUInLCAnQic9J0FCJywgJ0MnPSdDRCcsICdEJz0nQ0QnKQ0KDQphbmFseXNpc19kYXRhX3N0YW5kJGdyYWRlIDwtIGdyYWRlX2Fzc2lnbnNbYW5hbHlzaXNfZGF0YV9zdGFuZCRncmFkZV0NCg0KcmVnVGFzayA8LSBtbHI6Om1ha2VDbGFzc2lmVGFzayhkYXRhPWFuYWx5c2lzX2RhdGFfc3RhbmQsIHRhcmdldD0nZ3JhZGUnKQ0KDQpiaW5DbGFzcyA8LSBtbHI6Om1ha2VMZWFybmVyKCdjbGFzc2lmLmJpbm9taWFsJywgcHJlZGljdC50eXBlPSdwcm9iJywgdHlwZT0nZGlzY3JldGUnLCBkZWY9J2xvZ2l0JywgY29uc3RyPSdsb2dpdCcpDQoNCg0KbWxyOjpnZXRMZWFybmVyUGFyYW1TZXQoYmluQ2xhc3MpDQoNCm1scjo6c2V0SHlwZXJQYXJzKGJpbkNsYXNzLCB0eXBlPSdkaXNjcmV0ZScsIGRlZj0nbG9naXQnLCBjb25zdHI9J2xvZ2l0JywgKQ0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0K